<?php

namespace app\controllers;

use api\models\custom\Identity;
use app\models\Config;
use app\models\Message;
use app\models\QuarterSetting;
use app\models\User;
use app\models\UserLog;
use Yii;
use yii\base\Exception;
use yii\base\UserException;
use yii\helpers\Json;
use yii\web\Controller;

class BaseController extends Controller {
    /**
     * @param array $roleFilter
     * @param bool $unloginException
     * @return \app\models\User|null
     * @throws UserException
     */
    protected function check($roleFilter = [], $unloginException = true) {
        /** @var Identity $identity */
        $identity = Yii::$app->user->identity;
        if($identity) {
            $user = $identity->user;
            if($user) {
                if(empty($roleFilter) || in_array($user->role, $roleFilter)) {
                    return $user;
                }
            }
        }
        if($unloginException) {
            throw new UserException('未登录或无权操作');
        } else {
            return null;
        }
    }

    // 检查当前是否能进行操作
    protected function checkModify() {
        $model = QuarterSetting::find()->andWhere(['is_close'=>false,'is_open'=>true,])->exists();
        if(!$model) {
            throw new UserException('当前没有开启的财年，无法进行任何操作');
        }
        $user = $this->check();
        if($user->current_currency<0) {
            throw new UserException('当前货币小于0，已破产');
        }
        return $model;
    }

    // 记录日志，或者记录资金修改
    protected function log($action, $entry, $currency_change = 0, $allowMinus = false) {
        $user = $this->check();
        $this->logForUser($user, $action, $entry, $currency_change, $allowMinus);
    }

    // 记录日志，或者记录资金修改
    protected function logForUser(User $user, $action, $entry, $currency_change = 0, $allowMinus = false) {
        $log = new UserLog();
        $log->user_id = $user->id;
        $log->action = (string)$action;
        $log->entry = (string)$entry;
        $log->current_currency = $user->current_currency;
        $log->currency_change = $currency_change;
        if($currency_change) {
            $user->current_currency = round($user->current_currency + $currency_change, 2);
            if($user->current_currency < 0 && $currency_change<0 && !$allowMinus) {
                throw new UserException("资金不足，用户:{$user->id}，操作:{$action}");
            }
        }
        $this->transaction(function() use($log, $user) {
            $log->save();
            $user->save();
        });
    }

    // 记录消息
    protected function message(User $user, $title, $link, $class) {
        $message = new Message();
        $message->user_id = $user->id;
        $message->title = (string)$title;
        $message->link = (string)$link;
        $message->color = (string)$class;
        $message->if_read = false;
        $message->save();
    }

    /**
     * 用于开启事务处理
     * @param callable $f 必须要是一个返回DataMessage的函数
     * @param \yii\db\Connection|null $db
     * @param array[] [$params] 还可以传递任意多个参数
     * @return mixed
     * @throws Exception
     */
    protected function transaction(Callable $f, $db = null) {
        if (!$db) {
            $db = Yii::$app->db;
        }
        $trans = $db->beginTransaction();

        try {
            $params = func_get_args();
            array_shift($params);
            array_shift($params);
            $returnValue = call_user_func_array($f, $params);
        } catch (Exception $e) {
            $trans->rollBack();
            throw $e;
        }
        $trans->commit();
        return $returnValue;
    }

    public function getConfig($key, $default = null, $type = 'raw') {
        /** @var Config $config */
        $config = Config::findOne([
            'key' => $key
        ]);
        if ($config) {
            switch ($type) {
                case 'raw':
                    return $config->value;
                case 'json':
                    return Json::decode($config->value);
                case 'array':
                    return explode(',',$config->value);
                case 'int':
                    return (int)$config->value;
                case 'double':
                    return (double)$config->value;
            }
        } else {
            return $default;
        }
    }
}
